/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.SPI;

import com.aduib.boot.common.SPI.metadata.ConstructorMetaData;
import com.aduib.boot.common.SPI.metadata.FieldMetaData;
import com.aduib.boot.common.SPI.metadata.MetaDataBuilder;
import com.aduib.boot.common.SPI.metadata.MethodMetaData;
import com.aduib.boot.common.util.ClassUtils;

import java.util.List;
import java.util.Objects;

/**
 * @description: AbstractSPIDefinition
 * @author: zzh
 * @date: 2021/9/18 16:06
 */
public abstract class AbstractSPIDefinition implements SPIDefinition {

  private String name;

  private Class<?> clazz;

  private String filePath;

  private SPIRole spiRole;

  private Class<?> superClass;

  private Class<?>[] interfaces;

  private List<ConstructorMetaData> constructorMetaDataList;

  private List<FieldMetaData> fieldMetaDataList;

  private List<MethodMetaData> methodMetaDataList;

  public AbstractSPIDefinition() {}

  public AbstractSPIDefinition(String name, Class<?> clazz, String filePath, SPIRole spiRole, Class<?> superClass, Class<?>[] interfaces) {
    this.name = name;
    this.clazz = clazz;
    this.filePath = filePath;
    this.spiRole = spiRole;
    this.superClass = superClass;
    this.interfaces = interfaces;
    this.constructorMetaDataList= MetaDataBuilder.buildConstructorMetaData(clazz, (ConfigurableSPIFactory) SPILoader.INSTANCE);
    this.fieldMetaDataList= MetaDataBuilder.buildFieldMetaData(clazz, (ConfigurableSPIFactory) SPILoader.INSTANCE);
    this.methodMetaDataList= MetaDataBuilder.buildMethodMetaData(clazz, (ConfigurableSPIFactory) SPILoader.INSTANCE);
  }

  public AbstractSPIDefinition(String name, Class<?> clazz, String filePath, SPIRole spiRole) {
    this(name,clazz,filePath,spiRole,ClassUtils.getSuperclass(clazz),ClassUtils.getInterfaceClass(clazz));
  }

  public AbstractSPIDefinition(String name, Class<?> clazz, String filePath) {
    this.name = name;
    this.clazz = clazz;
    this.filePath = filePath;
    this.spiRole = getSpiRole();
  }

  public AbstractSPIDefinition(String name, Class<?> clazz,SPIRole spiRole) {
    this(name,clazz,ClassUtils.getClassFilePath(clazz),spiRole);
  }

  @Override
  public String getFilePath() {
    return filePath;
  }

  @Override
  public void setFilePath(String filePath) {
    this.filePath = filePath;
  }

  @Override
  public String getName() {
    return name;
  }

  @Override
  public void setName(String name) {
    this.name = name;
  }

  @Override
  public ClassLoader getClassLoader() {
    return getClass().getClassLoader();
  }

  @Override
  public Class<?> getSPIClass() {
    return clazz;
  }

  @Override
  public void setSPIClass(Class<?> clazz) {
    this.clazz = clazz;
  }

  @Override
  public Class<?> getSuperClass() {
    return superClass;
  }

  @Override
  public Class<?>[] getInterfaces() {
    return interfaces;
  }

  @Override
  public SPIRole getRole() {
    return spiRole;
  }

  @Override
  public List<ConstructorMetaData> getConstructorMetaDataList() {
    return constructorMetaDataList;
  }

  @Override
  public List<FieldMetaData> getFieldMetaDataList() {
    return fieldMetaDataList;
  }

  @Override
  public List<MethodMetaData> getMethodMetaDataList() {
    return methodMetaDataList;
  }

  public abstract SPIRole getSpiRole();

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    AbstractSPIDefinition that = (AbstractSPIDefinition) o;
    return Objects.equals(name, that.name)
        && Objects.equals(clazz, that.clazz)
        && Objects.equals(filePath, that.filePath);
  }

  @Override
  public int hashCode() {
    return Objects.hash(name, clazz, filePath);
  }
}
